﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace MLRobotic.Tower.Common
{
    public class Log
    {
        public enum LogLevel { Debug = 3, Info = 2, Error = 1, Off = 0 }

        #region Static
        private const string _logDirectory = @"\MLRobotic.Tower";
        private static Stopwatch _watch = new Stopwatch();
        private static LogLevel _level = LogLevel.Info;
        private static string _folder;
        private static StreamWriter _file = null;

        static Log()
        {
            _watch.Start();
            LogFolder = Path.Combine(_logDirectory, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
        }

        public static LogLevel Level
        { 
            get
            { 
                return _level;
            } 
            set
            { 
                if (value > LogLevel.Off)
                {
                    try
                    {
                        if (!Directory.Exists(_folder))
                            Directory.CreateDirectory(_folder);

                        PurgeDirectory(_folder);

                        if (_file == null)
                            _file = File.AppendText(Path.Combine(_folder, "Log.txt"));
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine("!!! PURGE DIRECTORY FAILED : " + ex.Message);
                    }
                }

                _level = value;
            }
        }

        /// <summary>
        /// NOT THREAD SAFE - FOR TEST PURPOSE
        /// </summary>
        public static string LogFolder
        {
            get
            { 
                return _folder;
            }
            set
            {
                _folder = value;

                if (Level > LogLevel.Off)
                {
                    try
                    {
                        if (!Directory.Exists(_folder))
                            Directory.CreateDirectory(_folder);

                        PurgeDirectory(_folder);

                        if (_file != null)
                            _file.Close();

                        _file = File.AppendText(Path.Combine(_folder, "_log.txt"));
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine("!!! PURGE DIRECTORY FAILED : " + ex.Message);
                    }
                }
            }
        }

        public static bool IsDebugEnabled()
        {
            return Level >= LogLevel.Debug && System.Diagnostics.Debug.Listeners.Count > 0;
        }

        public static bool IsInfoEnabled()
        {
            return Level >= LogLevel.Info;
        }

        public static bool IsErrorEnabled()
        {
            return Level >= LogLevel.Error;
        }

        public static void Flush()
        {
            _file.Flush();
        }

        private static void PurgeDirectory(string _folder)
        {
            int history = 7;
            var subDirs = Directory.GetDirectories(_logDirectory);
            if (subDirs.Count() > history)
            {
                foreach (var path in subDirs.OrderByDescending(p => p).Skip(history))
                    Directory.Delete(path, true);
            }
        }
        #endregion

        private string _name;
        private Stopwatch _elapsedWatch = new Stopwatch();

        public Log(string name)
        {
            _elapsedWatch.Start();
            _name = name;
        }

        public void Debug(string message)
        {
            if (IsDebugEnabled())
                Write(LogLevel.Debug, message);
        }

        public void DebugElapsed(string message)
        {
            if (IsDebugEnabled())
                Debug(message + " (" + _elapsedWatch.ElapsedMilliseconds + " ms)");
        }

        public void DebugStartWatch(string message)
        {
            if (IsDebugEnabled())
            {
                _elapsedWatch.Reset();
                _elapsedWatch.Start();
                Write(LogLevel.Debug, message);
            }
        }

        public void Info(string message)
        {
            if (IsInfoEnabled())
                Write(LogLevel.Info, message);
        }

        public void Error(string message)
        {
            if (IsErrorEnabled())
                Write(LogLevel.Error, message);
        }

        public void Error(string message, Exception ex)
        {
            if (IsErrorEnabled())
                Write(LogLevel.Error, message + " ---> " + ex.Message + " ---> " + ex.StackTrace);
        }

        private void Write(LogLevel level, string message)
        {
            try
            {
                string line = string.Format("{0} - {1} - {2} : {3}", _watch.Elapsed, level.ToString(), _name, message);
                System.Diagnostics.Debug.WriteLine(line);
                _file.WriteLine(line);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("!!! LOG FAILED : " + ex.Message);
            }
        }
    }
}
